/**
 * 数据同步服务
 * 负责管理前后端数据同步、离线数据处理、冲突解决等
 */

import { cache, CacheOptions } from '@/utils/cacheManager';
import { get, post, put, del } from '@/utils/request';
import { handleError } from '@/utils/errorHandler';

interface SyncItem {
  id: string;
  type: 'create' | 'update' | 'delete';
  resource: string;
  data: any;
  timestamp: number;
  retryCount: number;
  maxRetries: number;
}

interface SyncConfig {
  autoSync: boolean;
  syncInterval: number;
  maxRetries: number;
  batchSize: number;
  conflictResolution: 'client' | 'server' | 'manual';
}

interface SyncResult {
  success: boolean;
  synced: number;
  failed: number;
  conflicts: number;
  errors: any[];
}

class SyncService {
  private static instance: SyncService;
  private syncQueue: SyncItem[] = [];
  private isOnline = true;
  private isSyncing = false;
  private syncTimer?: any;
  
  private config: SyncConfig = {
    autoSync: true,
    syncInterval: 30000, // 30秒
    maxRetries: 3,
    batchSize: 10,
    conflictResolution: 'server'
  };
  
  static getInstance(): SyncService {
    if (!SyncService.instance) {
      SyncService.instance = new SyncService();
    }
    return SyncService.instance;
  }
  
  constructor() {
    this.initNetworkListener();
    this.loadSyncQueue();
    this.startAutoSync();
  }
  
  /**
   * 初始化网络监听
   */
  private initNetworkListener() {
    // uni-app网络状态监听
    if (typeof uni !== 'undefined') {
      uni.onNetworkStatusChange((res) => {
        this.isOnline = res.isConnected;
        if (this.isOnline && this.syncQueue.length > 0) {
          this.syncPendingItems();
        }
      });
      
      // 获取初始网络状态
      uni.getNetworkType({
        success: (res) => {
          this.isOnline = res.networkType !== 'none';
        }
      });
    }
    // Web环境网络监听
    else if (typeof window !== 'undefined') {
      window.addEventListener('online', () => {
        this.isOnline = true;
        if (this.syncQueue.length > 0) {
          this.syncPendingItems();
        }
      });
      
      window.addEventListener('offline', () => {
        this.isOnline = false;
      });
      
      this.isOnline = navigator.onLine;
    }
  }
  
  /**
   * 开始自动同步
   */
  private startAutoSync() {
    if (this.config.autoSync && !this.syncTimer) {
      this.syncTimer = setInterval(() => {
        if (this.isOnline && !this.isSyncing) {
          this.syncPendingItems();
        }
      }, this.config.syncInterval);
    }
  }
  
  /**
   * 停止自动同步
   */
  private stopAutoSync() {
    if (this.syncTimer) {
      clearInterval(this.syncTimer);
      this.syncTimer = undefined;
    }
  }
  
  /**
   * 配置同步服务
   */
  configure(config: Partial<SyncConfig>) {
    this.config = { ...this.config, ...config };
    
    // 重启自动同步
    this.stopAutoSync();
    if (this.config.autoSync) {
      this.startAutoSync();
    }
  }
  
  /**
   * 添加同步项到队列
   */
  addToQueue(
    type: 'create' | 'update' | 'delete',
    resource: string,
    data: any,
    options: { immediate?: boolean; maxRetries?: number } = {}
  ): string {
    const syncItem: SyncItem = {
      id: this.generateId(),
      type,
      resource,
      data,
      timestamp: Date.now(),
      retryCount: 0,
      maxRetries: options.maxRetries || this.config.maxRetries
    };
    
    this.syncQueue.push(syncItem);
    this.saveSyncQueue();
    
    // 立即同步
    if (options.immediate && this.isOnline) {
      this.syncItem(syncItem);
    }
    
    return syncItem.id;
  }
  
  /**
   * 同步单个项目
   */
  private async syncItem(item: SyncItem): Promise<boolean> {
    try {
      let response: any;
      
      switch (item.type) {
        case 'create':
          response = await post(`/api/${item.resource}`, item.data);
          break;
        case 'update':
          response = await put(`/api/${item.resource}/${item.data.id}`, item.data);
          break;
        case 'delete':
          response = await del(`/api/${item.resource}/${item.data.id}`);
          break;
      }
      
      // 同步成功，从队列中移除
      this.removeFromQueue(item.id);
      
      // 更新本地缓存
      this.updateLocalCache(item, response?.data);
      
      return true;
    } catch (error) {
      item.retryCount++;
      
      // 检查是否需要重试
      if (item.retryCount >= item.maxRetries) {
        // 达到最大重试次数，标记为失败
        this.handleSyncFailure(item, error);
        this.removeFromQueue(item.id);
      } else {
        // 保存更新的重试次数
        this.saveSyncQueue();
      }
      
      handleError(error, {
        logToConsole: true,
        showToast: false
      });
      
      return false;
    }
  }
  
  /**
   * 同步待处理项目
   */
  async syncPendingItems(): Promise<SyncResult> {
    if (this.isSyncing || !this.isOnline || this.syncQueue.length === 0) {
      return {
        success: true,
        synced: 0,
        failed: 0,
        conflicts: 0,
        errors: []
      };
    }
    
    this.isSyncing = true;
    
    const result: SyncResult = {
      success: true,
      synced: 0,
      failed: 0,
      conflicts: 0,
      errors: []
    };
    
    try {
      // 按批次处理
      const batches = this.chunkArray(this.syncQueue, this.config.batchSize);
      
      for (const batch of batches) {
        const batchPromises = batch.map(item => this.syncItem(item));
        const batchResults = await Promise.allSettled(batchPromises);
        
        batchResults.forEach((batchResult, index) => {
          if (batchResult.status === 'fulfilled' && batchResult.value) {
            result.synced++;
          } else {
            result.failed++;
            if (batchResult.status === 'rejected') {
              result.errors.push(batchResult.reason);
            }
          }
        });
        
        // 批次间延迟，避免服务器压力
        if (batches.length > 1) {
          await this.delay(1000);
        }
      }
      
      result.success = result.failed === 0;
    } catch (error) {
      result.success = false;
      result.errors.push(error);
      handleError(error);
    } finally {
      this.isSyncing = false;
    }
    
    return result;
  }
  
  /**
   * 获取资源数据（带缓存）
   */
  async getData<T>(
    resource: string,
    params: any = {},
    options: CacheOptions & { forceRefresh?: boolean } = {}
  ): Promise<T> {
    const cacheKey = this.generateCacheKey(resource, params);
    
    // 强制刷新或离线时直接从缓存获取
    if (options.forceRefresh || !this.isOnline) {
      if (!this.isOnline) {
        const cached = cache.get<T>(cacheKey, options.storage);
        if (cached) {
          return cached;
        }
        throw new Error('No cached data available offline');
      }
    }
    
    return cache.getOrSet(
      cacheKey,
      async () => {
        const response = await get(`/api/${resource}`, params);
        return response.data;
      },
      {
        expireTime: 5 * 60 * 1000, // 5分钟
        storage: 'local',
        ...options
      }
    );
  }
  
  /**
   * 创建资源
   */
  async createData<T>(resource: string, data: any, options: { sync?: boolean } = {}): Promise<T> {
    const tempId = this.generateTempId();
    const tempData = { ...data, id: tempId, _temp: true };
    
    // 立即更新本地缓存
    this.updateLocalCacheForResource(resource, tempData, 'create');
    
    if (this.isOnline && options.sync !== false) {
      try {
        const response = await post(`/api/${resource}`, data);
        // 用真实数据替换临时数据
        this.replaceLocalCacheItem(resource, tempId, response.data);
        return response.data;
      } catch (error) {
        // 添加到同步队列
        this.addToQueue('create', resource, data);
        throw error;
      }
    } else {
      // 离线或不同步，添加到队列
      this.addToQueue('create', resource, data);
      return tempData as T;
    }
  }
  
  /**
   * 更新资源
   */
  async updateData<T>(resource: string, id: string, data: any, options: { sync?: boolean } = {}): Promise<T> {
    const updateData = { ...data, id };
    
    // 立即更新本地缓存
    this.updateLocalCacheForResource(resource, updateData, 'update');
    
    if (this.isOnline && options.sync !== false) {
      try {
        const response = await put(`/api/${resource}/${id}`, data);
        this.updateLocalCacheForResource(resource, response.data, 'update');
        return response.data;
      } catch (error) {
        // 添加到同步队列
        this.addToQueue('update', resource, updateData);
        throw error;
      }
    } else {
      // 离线或不同步，添加到队列
      this.addToQueue('update', resource, updateData);
      return updateData as T;
    }
  }
  
  /**
   * 删除资源
   */
  async deleteData(resource: string, id: string, options: { sync?: boolean } = {}): Promise<void> {
    // 立即从本地缓存移除
    this.updateLocalCacheForResource(resource, { id }, 'delete');
    
    if (this.isOnline && options.sync !== false) {
      try {
        await del(`/api/${resource}/${id}`);
      } catch (error) {
        // 添加到同步队列
        this.addToQueue('delete', resource, { id });
        throw error;
      }
    } else {
      // 离线或不同步，添加到队列
      this.addToQueue('delete', resource, { id });
    }
  }
  
  /**
   * 获取同步状态
   */
  getSyncStatus(): {
    isOnline: boolean;
    isSyncing: boolean;
    queueLength: number;
    lastSyncTime?: number;
  } {
    return {
      isOnline: this.isOnline,
      isSyncing: this.isSyncing,
      queueLength: this.syncQueue.length,
      lastSyncTime: this.getLastSyncTime()
    };
  }
  
  /**
   * 清空同步队列
   */
  clearSyncQueue(): void {
    this.syncQueue = [];
    this.saveSyncQueue();
  }
  
  /**
   * 手动触发同步
   */
  async forcSync(): Promise<SyncResult> {
    return this.syncPendingItems();
  }
  
  // 私有方法
  
  private generateId(): string {
    return Date.now().toString(36) + Math.random().toString(36).substr(2);
  }
  
  private generateTempId(): string {
    return 'temp_' + this.generateId();
  }
  
  private generateCacheKey(resource: string, params: any): string {
    const paramString = Object.keys(params)
      .sort()
      .map(key => `${key}=${params[key]}`)
      .join('&');
    return `${resource}${paramString ? '?' + paramString : ''}`;
  }
  
  private removeFromQueue(id: string): void {
    const index = this.syncQueue.findIndex(item => item.id === id);
    if (index > -1) {
      this.syncQueue.splice(index, 1);
      this.saveSyncQueue();
    }
  }
  
  private saveSyncQueue(): void {
    try {
      const queueData = JSON.stringify(this.syncQueue);
      if (typeof uni !== 'undefined') {
        uni.setStorageSync('syncQueue', queueData);
      } else if (typeof localStorage !== 'undefined') {
        localStorage.setItem('syncQueue', queueData);
      }
    } catch (error) {
      console.warn('Failed to save sync queue:', error);
    }
  }
  
  private loadSyncQueue(): void {
    try {
      let queueData: string | null = null;
      
      if (typeof uni !== 'undefined') {
        queueData = uni.getStorageSync('syncQueue');
      } else if (typeof localStorage !== 'undefined') {
        queueData = localStorage.getItem('syncQueue');
      }
      
      if (queueData) {
        this.syncQueue = JSON.parse(queueData);
      }
    } catch (error) {
      console.warn('Failed to load sync queue:', error);
      this.syncQueue = [];
    }
  }
  
  private updateLocalCache(item: SyncItem, serverData?: any): void {
    // 更新相关的缓存项
    const cacheKeys = this.getRelatedCacheKeys(item.resource);
    cacheKeys.forEach(key => {
      cache.remove(key, 'local');
    });
  }
  
  private updateLocalCacheForResource(resource: string, data: any, operation: 'create' | 'update' | 'delete'): void {
    // 这里可以实现更复杂的本地缓存更新逻辑
    const cacheKeys = this.getRelatedCacheKeys(resource);
    cacheKeys.forEach(key => {
      cache.remove(key, 'local');
    });
  }
  
  private replaceLocalCacheItem(resource: string, tempId: string, realData: any): void {
    // 替换临时数据为真实数据
    const cacheKeys = this.getRelatedCacheKeys(resource);
    cacheKeys.forEach(key => {
      cache.remove(key, 'local');
    });
  }
  
  private getRelatedCacheKeys(resource: string): string[] {
    // 获取与资源相关的所有缓存键
    // 这里可以根据实际需求实现更复杂的逻辑
    return [resource, `${resource}/list`];
  }
  
  private handleSyncFailure(item: SyncItem, error: any): void {
    console.error(`Sync failed for item ${item.id}:`, error);
    
    // 可以在这里实现失败处理逻辑，比如通知用户
    // 或者将失败的项目保存到特殊的失败队列中
  }
  
  private getLastSyncTime(): number | undefined {
    try {
      let lastSyncTime: string | null = null;
      
      if (typeof uni !== 'undefined') {
        lastSyncTime = uni.getStorageSync('lastSyncTime');
      } else if (typeof localStorage !== 'undefined') {
        lastSyncTime = localStorage.getItem('lastSyncTime');
      }
      
      return lastSyncTime ? parseInt(lastSyncTime) : undefined;
    } catch {
      return undefined;
    }
  }
  
  private chunkArray<T>(array: T[], size: number): T[][] {
    const chunks: T[][] = [];
    for (let i = 0; i < array.length; i += size) {
      chunks.push(array.slice(i, i + size));
    }
    return chunks;
  }
  
  private delay(ms: number): Promise<void> {
    return new Promise(resolve => setTimeout(resolve, ms));
  }
}

// 导出单例实例
export const syncService = SyncService.getInstance();

// 导出便捷方法
export const sync = {
  configure: (config: Partial<SyncConfig>) => syncService.configure(config),
  getData: <T>(resource: string, params?: any, options?: CacheOptions & { forceRefresh?: boolean }) => 
    syncService.getData<T>(resource, params, options),
  createData: <T>(resource: string, data: any, options?: { sync?: boolean }) => 
    syncService.createData<T>(resource, data, options),
  updateData: <T>(resource: string, id: string, data: any, options?: { sync?: boolean }) => 
    syncService.updateData<T>(resource, id, data, options),
  deleteData: (resource: string, id: string, options?: { sync?: boolean }) => 
    syncService.deleteData(resource, id, options),
  getStatus: () => syncService.getSyncStatus(),
  forceSync: () => syncService.forcSync(),
  clearQueue: () => syncService.clearSyncQueue()
};

// 导出类型
export type { SyncConfig, SyncResult, SyncItem };